<template>
  <div>
    <el-upload
      class="upload-demo"
      action="https://jsonplaceholder.typicode.com/posts/"
      :on-change="handleChange"
      :http-request="putinMirror"
      :file-list="fileList"
    >
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传图片/视频/文件压缩包，且不超过1G</div>
    </el-upload>
  </div>
</template>

<script>
import SparkMD5 from 'spark-md5';

export default {
  name: "JsPage",
  data() {
    return {
      fileList: []
    };
  },
  methods: {
    handleChange(file, fileList) {
      console.log('文件上传change事件:', file, fileList);
    },
    async putinMirror(file) {
      const sliceSize = 5 * 1024 * 1024; // 每个文件切片大小定为5MB
      const maxFileSize = 1 * 1024 * 1024 * 1024; // 文件大小限制为最大1个G

      const blob = file.file;
      const fileSize = blob.size; // 文件大小
      const fileName = blob.name; // 文件名
      const totalSlices = Math.ceil(fileSize / sliceSize); // 计算文件切片总数
      // MD5加密计算
      const reader = new FileReader();
      const identifierPrefix = await new Promise((resolve, reject) => {
        reader.onload = () => {
          const spark = new SparkMD5.ArrayBuffer();
          spark.append(reader.result);
          const hash = spark.end();
          resolve(hash); // 使用MD5计算结果作为identifier前缀
        };
        reader.onerror = () => {
          reject(new Error('文件读取错误'));
        };
        reader.readAsArrayBuffer(blob);
      });

      if (fileSize <= maxFileSize) {
        // 循环上传分片
        for (let i = 0; i < totalSlices; i++) {
          const start = i * sliceSize;
          const chunk = blob.slice(start, Math.min(fileSize, start + sliceSize));
          const formData = new FormData();
          const fileType = fileName.split('.').pop();
          const identifier = identifierPrefix;
          formData.append("identifier", identifier);
          formData.append("file", chunk);
          formData.append("chunkNumber", i + 1);
          formData.append("filename", fileName);
          formData.append("totalSize", fileSize);
          formData.append("chunkSize", totalSlices);
          formData.append("totalChunks", chunk.size);
          formData.append("fileType", fileType);

          // 校验分片是否存在
          // const missingChunks = await this.checkChunkExist(formData);
          // if (missingChunks === true) {
          //   debugger
          //   console.log("分片已全部存在，跳过上传");
          //   continue;
          // } else if (Array.isArray(missingChunks)) {
          //   if (missingChunks.length < totalSlices) {
          //     console.log("部分分片已存在，继续上传缺失的分片");
          //     await this.uploadExcleAndZip(formData, missingChunks);
          //   } else {
          //     console.log("所有分片都不存在，直接执行分片上传");
          //     await this.uploadExcleAndZip(formData);
          //   }
          // } else {
          //   console.error("校验分片失败，取消上传");
          //   break;
          // }

          const res = await this.uploadExcleAndZip(formData); // 上传分片
          console.log(res);
          if (res.errCode === 0) {
            setTimeout(() => {
              if (i + 1 === totalSlices) {
                // 上传成功后执行合并操作
                const mergeFormData = new FormData();
                mergeFormData.append("identifier", identifier);
                mergeFormData.append("filename", fileName);
                mergeFormData.append("totalChunks", totalSlices);
                mergeFormData.append("fileType", fileType);
                this.mergeChunks(mergeFormData);
                this.$message({
                  message: '上传成功',
                  type: 'success'
                });
              }
            }, 1000);
          }
        }
      } else { // 文件大小超出最大限制
        this.$message({
          message: '文件大小超出1G',
          type: 'error'
        });
      }
    },

    // 校验分片是否存在
async checkChunkExist(formData) {
  const params = new URLSearchParams(formData);
  const url = `/voide/jiaoChunk?${params.toString()}`;
  const response = await this.$axios.get(url).catch(error => {
    console.error('校验分片失败:', error);
    return null;
  });
  
  if (response && response.data) {
    const { exist, missingChunks } = response.data;
    
    if (exist) {
      console.log("分片已存在，跳过上传");
      return true; // 分片全部已存在，无需再上传
    } else if (missingChunks === null) {
      console.log("文件不存在，执行上传");
      await this.uploadExcleAndZip(formData); // 执行上传逻辑
      return true; // 文件不存在，直接返回true表示上传完成
    } else {
      console.log("部分分片已存在，继续上传缺失的分片");
      console.log('缺失的分片:', missingChunks);
      return missingChunks; // 返回缺失的分片数组
    }
  }

  console.error(`校验分片失败，取消上传`);
  return null;
},

    uploadExcleAndZip(formData, missingChunks = []) {
      // 上传分片
      return this.$axios.post('/voide/chunk', formData)
        .then(res => {
          console.log('上传成功:', formData);
          return {
            errCode: 0
          };
        });
    },

    mergeChunks(mergeFormData) {
      // 合并分片
      return this.$axios.post('/voide/merge', mergeFormData)
        .then(res => {
          console.log('合并成功:', mergeFormData);
        })
        .catch(error => {
          console.log('合并失败:', mergeFormData);
        });
    }
  }
}
</script>

<style>
.uploader-example {
  width: 100%;
  padding: 15px;
  margin: 0px auto 0;
  font-size: 12px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {
  margin-right: 4px;
}
.uploader-example .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>
